# -*- coding: utf-8 -*-
# Демонстрация типов данных в Python
# Использован интерпретатор http://python.org/download/ - Python 2.7
from cmath import sin, sqrt

# Отличия переменной, объекта и ссылки
print u"1. Понятие переменной, объекта, ссылки, семантика оператора присваивания"
print u"Переменная присываивается по значению"
# Используется приваивание "по значению"
a = 3
b = a
b = 4
print "a =", a, ' b =', b # a = 3  b = 4, переменная a не изменилась после изменения b

# Используется присваивание "по ссылке"
class MyClass: field = 1 # Создали класс MyClass с одним полем field
a = MyClass()
a.field = 3
b = MyClass()
b = a #  Теперь b и a ссылаются на один и тот же объект
b.field = 4
print "a.field =", a.field, ' b.field =', b.field # a.field = 4  b.field = 4

print u'2. Операторы управления потоком вычислений'
if (3 > 2) or (1==2) and (3==1+2): # Условие
  print "3 > 2" # При выполнении условия
else: # Необязательный else
  print "xxx" # Если условие не выполняется

i = 23  # Задаём значение переменной
while i > 0: # Пока больше 0
  print i, # Печатаем в строку
  i /= 2  # Деление нацело
print # Переводим на новую строку. Получилось: 23 11 5 2 1

for str in ['first string', 'second', 'third']:
  print str
for i in range(1999,2010):
  print i, # Получилось: 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009

print u'3. Функции, определение и вызов функций, формальные и актуальные параметры, рекурсия'
# Определение рекурсивной функции вычисления факториала
def Factorial(n):
  # Барьерное условие. Ограничивает область применимости функции
  # "Мёртвые программы не лгут!"
  assert n > 0
  if n == 1:
    return 1
  else:
    return n * Factorial(n - 1)

# print Factorial(-1) # При вызове будет ошибка с выводом всей
# последовательность  

# Факториал при помощи тернарного оператора в Python
def Factorial2(n): return 1 if n == 1 else n * Factorial(n - 1)
#   (Что-то) если (условие) иначе (что-то другое)
#  В С/C++: (условие) ? (что-то) : (что-то другое)

# Пример вызова обеих функций
print "3! =", Factorial(3), ' ', Factorial2(3)

# Генератор
# 1 1 2 3 5 8 13
def fibonacci(max): # генератор (а не функция, т.к. оператор return заменён на yield)
  a, b = 0, 1
  while a < max:
    yield a         # return a, + запоминаем место рестарта для следующего вызова
    a, b = b, a + b # параллельное присваивание, которое выполняется одновременно и параллельно

for n in fibonacci(100):   # используем генератор fibonacci() как итератор
  print n, # печатаем все числа Фибоначчи меньшие 100 через пробел
print

# Вычисление наименьшего общего делителя, % - деление по модулю (mod)
def GCD(a, b): return a if b == 0 else GCD(b, a % b)

print "GCD(30,45) =", GCD(30, 45)  # Результат: GCD(30,45) = 15

print u"4. Представление чисел в языке Python, операции над числами"

from math import * # Подключаем функции библиотеки math

print 2 ** 100 # возведение 2 в степень 100
print sin(pi * 0.5)  # вычисление синуса от половины пи
print 3.23e10 # Экспоненциальная форма записи чисел
print u"Python работает с комплексными числами"
x = 1 + 2j # целое число и мнимое число
print x * 2
print u"Решим квадратное уравнение x*x+1=0 с комплексными корнями"
a,b,c = 1,0,1
D = b*b-4*a*c
dd = ((-sqrt(D), sqrt(D)) if D > 0 else (-1j * sqrt(-D), 1j * sqrt(-D)))
x = [(-b+d)/2*a for d in dd]
print x

i = 1
for c in u"Привет!":
  print i,c
  i += 1

print u"Привет!"
print u"5. представление строк в языке Python, простые и Unicode-строки, основные операции"
str = "String " + '2'
print str, ' ', str.upper(), ' ', str.lower(), ' ', str.center(20)
print str.count('t') # Количество букв t в строке
unicodeStr = unicode(u'Привет')
print unicodeStr, ' ', type(unicodeStr)
myString = "Не юникод-строка"
print u"Переводим её в Unicode и печатаем: ", myString.decode("utf-8") #
print unicodeStr.encode("utf-8")

# кодировка текста, Unicode (основные концепции, классы символов, уникальность представления);
s1 = "Тест"
s2 = u"Тест"
print s1, ' ', s2
#assert s1 == s2

# Основные структуры данных языка Python:
# списки (lists), тюплы (tuples), словари (dictionaries, dicts).
a = [1, 2, "a"]              # список
b = (1, 2, "a")              # кортеж, тюплы (tuples)
c = {'a': 1, 'b': 'B'}       # словарь
l = ['A', 'B', 'C', 'D', 'E'] # Исходный список
print u"срез от нулевого до второго промежутка ", l[1:5] # ['A', 'B']
print u"срез от второго до второго с конца элемента", l[1:-2] # ['B', 'C']
print u"каждый второй элемент начиная с первого", l[1::2] # ['B', 'D']
print u"все элементы в обратном порядке", l[::-1]  # ['E', 'D', 'C', 'B', 'A']

tuple = (1, 3, 2, "a")  # кортеж, тюпл (tuple)
print type(tuple), ' ', tuple  # <type 'tuple'>   (1, 3, 2, 'a')
for i in tuple: print i,  # 1 3 2 a
t = 12345, 54321, 'hello!' # tuple packing
print t # (12345, 54321, 'hello!')

